package com.itheima.d4_byte_stream;

import java.io.*;

/**
 * 目标：掌握文件字节输入流，每次读取一个字节。
 * FileInputStream（文件字节输入流）
 * 作用：以内存为基准，可以把磁盘文件中的数据以字节的形式读入到内存中去。
 *
 * 构造器                                      说明
 * public FileInputStream(File file)        创建字节输入流管道与源文件接通
 * public FileInputStream(String pathname)  创建字节输入流管道与源文件接通     磊哥说这个用的多，填文件路径就可以了，因为上面那个还要创建文件对象多此一举
 *
 * 方法名称
 *  public int read()   每次读取一个字节返回，如果发现没有数据可读会返回-1.
 *  public int read(byte[] buffer)  每次用一个字节数组去读取数据，返回字节数组读取了多少个字节，如果发现没有数据可读会返回-1.
 *
 * FileInputStream继承InputStream类，源码：
 * public class FileInputStream extends InputStream
 * InputStream实现Closeable接口源码：
 * public abstract class InputStream implements Closeable
 * Closeable接口继承AutoCloseable接口：
 * public interface Closeable extends AutoCloseable
 * AutoCloseable接口源码：
 * public interface AutoCloseable
 *
 *
 *  注意:
 *      使用FileInputStream每次读取一个字节，读取性能较差，并且读取汉字输出会乱码。
 *
 */
public class FileInputStreamTest1 {
    public static void main(String[] args) throws Exception {
        // 1、创建文件字节输入流管道，与源文件接通。
        //FileInputStream is1 = new FileInputStream(new File("Day08File-Io-App\\src\\itheima01.txt"));
        //把上面的用多态写法，并且因为系统担心路径不对或者文件不存在，抛异常：Unhandled exception: java.io.FileNotFoundException
        //InputStream是FileInputStream的父类，并且更容易看到右边是实现类，左边是父类，子类的对象是可以给父类来接收的，关系一目了然
        // InputStream is1 = new FileInputStream(new File("Day08File-Io-App\\src\\itheima01.txt"));   //相对路径

        // 简化写法：推荐使用。
        /*源码：
        public FileInputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null);
        输入的路径不为空的话，就会封装为一个file对象 ，然后由this调用FileInputStream的构造器
    }
         */
        InputStream is = new FileInputStream(("Day08File-Io-App\\src\\itheima01.txt"));

        // 2、开始读取文件的字节数据。
        // public int read():每次读取一个字节返回，如果没有数据了，返回-1.
        int b1 = is.read();
        System.out.println(b1);
        System.out.println("把读取到的字节b1转换为char类型的字符"+(char)b1);
        System.out.println("---------也可以不用(char)b1的形式转换读到的字节，不行，解码要字节数组");
        String string = new String(String.valueOf(b1));
        System.out.println(string);
        //  String(byte[] bytes)       通过使用平台的默认字符集解码指定的字节数组来构造新的 String
        //  String(byte[] bytes, String charsetName)    通过指定的字符集解码指定的字节数组来构造新的 String

        int b2 = is.read();
        System.out.println(b2);
        System.out.println((char) b2);

        int b3 = is.read();
        System.out.println(b3);
        System.out.println((char) b3);

        System.out.println("-----------上面已经读取了三个字节，那么接下来的循环就不能读取前三个字节---------");

        // 3、使用循环改造上述代码
        int b; // 用于记住读取的字节。
        while ((b = is.read()) != -1){      //先看小括号里面的内容，然后从等号的从右往左执行，先通过这个文件字节输入流到文件里面读一个字节
            System.out.print((char) b);
        }

        // 这种读取方法方案的问题如下：
        // 读取数据的性能很差！由于文件是在硬盘里面的，程序是在内存中执行的，不能直接去硬盘中读文件，
        // 所以是要调用系统相关的硬件资源去硬盘中读取数据，这两步相对内存来说都是很慢，应该减少这两个步骤的发生
        // 读取汉字输出会乱码！！无法避免的！！：因为现在是UTF-8编码解码，汉字占三个字节，但是每次都是读一个字节出来，所以把汉字的字节给拆散了，自然输出的就像乱码了
        // 流使用完毕之后，必须关闭！释放系统资源！
        is.close();

        System.out.println();

        System.out.println("----------自己试一试---------------");
        InputStream zeng1 = new FileInputStream("Day08File-Io-App\\src\\itheima02.txt");
        int z = zeng1.read();
        System.out.println(z);
        System.out.println((char) z);
        System.out.println("-----------循环------------------");
        int a;
        while ( (a = zeng1.read()) != -1){
            System.out.println((char) a);
        }
        zeng1.close();
    }
}
